home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Text⁄Files / Writeswell Jr. 1.0.2 Master / Writeswell Jr. Source / DoChecking.c < prev    next >
Text File  |  1992-12-08  |  13KB  |  556 lines

  1. /* DoChecking.c
  2.  * Functions that actually do the calls to the Word Services servers.
  3.  * ©1992 Working Software, Inc.
  4.  * This source code is copyrighted.  Permission is granted to use the Word Services
  5.  * portion of the Writeswell Jr. source code in your own programs, but you 
  6.  * may not distribute the Writeswell Jr. word-processor code as a 
  7.  * commercial product.  If you modify the code, please do not call it 
  8.  * Writeswell Jr. (or Writeswell.)  This will ensure that people understand the 
  9.  * program and don’t have to deal with a number of different versions with 
  10.  * who-knows-what going on in the code.
  11.  * 
  12.  * Writeswell Jr. and Writeswell are trademarks of Working Software, Inc.
  13.  * 28 Dec 91 Mike Crawford
  14.  */
  15.  
  16. #include <Aliases.h>
  17. #include <Processes.h>
  18. #include <AppleEvents.h>
  19. #include <AEObjects.h>
  20. #include <AEPackObject.h>
  21. #include <AERegistry.h>
  22. #include "TBConstants.h"
  23. #include "TBGlobals.h"
  24. #include "WordServices.h"
  25. #include "AppEvents.h"
  26. #include "ObWind.h"
  27. #include "ObText.h"
  28. #include "Gripe.h"
  29. #include "Prefs.h"
  30. #include "DoChecking.h"
  31. #include "FindProcess.h"
  32. #include "TableCheck.h"
  33.  
  34. #define LAUNCH_BY_EVENT            /* Undef this to use Proc Mgr instead of Finder AE */
  35.  
  36. #define kLaunchTimeout    1800    /* If the speller's on a floppy, it may take a while */
  37. #define kBatchTimeout    600
  38.  
  39. OSErr LaunchSpeller( AliasHandle aliasHdl );
  40.  
  41. OSErr DoSpellCheck( short serviceNumber )
  42. {
  43.     OSErr            err;
  44.     AEDesc            docSpecifier;
  45.     AEDesc            textDescriptor;
  46.     AEDesc            textSpecifier;
  47.     AEAddressDesc    spellerAddr;
  48.     AppleEvent        btchEvent;
  49.     AppleEvent        replyEvent;
  50.     WWJrPrefsHdl    prefHdl;
  51.     ServiceType        servType;
  52.  
  53.     prefHdl = GetPrefHandle();
  54.     if ( !prefHdl ){
  55.         Gripe( "\pCannot get preferences handle" );
  56.         return resNotFound;
  57.     }
  58.  
  59.     err = OpenSpeller( serviceNumber, &spellerAddr, &servType );
  60.     if ( err ){
  61.         Gripe( "\pOpenSpeller failed to connect with speller" );
  62.         return err;
  63.     }
  64.  
  65.     switch ( servType ){
  66.         case kBatchService:
  67.             if ( (*prefHdl)->sendByList ){
  68.                 err = DoBatchCheck( &spellerAddr );
  69.                 if ( err ){
  70.                     Gripe( "\pDoBatchCheck failed" );
  71.                     return err;
  72.                 }
  73.             }else{
  74.                 err = DoBatchTableCheck( &spellerAddr );
  75.                 if ( err ){
  76.                     Gripe( "\pDoBatchTableCheck failed" );
  77.                     return err;
  78.                 }
  79.             }
  80.             break;
  81.         case kInteractiveService:
  82.             Gripe( "\pInteractive service is not implemented yet" );
  83.             return noErr;
  84.             break;
  85.         default:
  86.             Gripe( "\pBad service type code in preferences file" );
  87.             return noErr;
  88.     }
  89.  
  90.     return noErr;
  91. }
  92.  
  93. OSErr DoBatchCheck( AEAddressDesc *spellerAddrPtr )
  94. {
  95.     OSErr            err;
  96.     AEDesc            textSpecifier;
  97.     AppleEvent        btchEvent;
  98.     AppleEvent        replyEvent;
  99.     WWJrPrefsHdl    prefHdl;
  100.     AEDescList        textSpecList;            /* 1.0d7 */
  101.     long            index;                    /* 1.0d7 */
  102.  
  103.     /* We make an object specifier that refers to _our_own_ window
  104.      */
  105.  
  106.     err = CreateTextSpecifier( 1L, 1L, &textSpecifier );
  107.     
  108.     if ( err ){
  109.         Gripe( "\pCreateTextSpecifier failed" );
  110.         return err;
  111.     }
  112.  
  113.     prefHdl = GetPrefHandle();
  114.     if ( !prefHdl ){
  115.         Gripe( "\pCannot get preferences handle" );
  116.         return resNotFound;
  117.     }
  118.     
  119.     if ( (*prefHdl)->checkSel ){
  120.         /* Make a formRange descriptor that gives the selection range */
  121.  
  122.         Gripe( "\pSelection-only checking is not yet implemented" );
  123.         return noErr;
  124.     }
  125.  
  126.     /* Create the event to send to the speller */
  127.     
  128.     err = AECreateAppleEvent( kWordServicesClass,
  129.                                 kWSBatchCheckMe,
  130.                                 spellerAddrPtr,
  131.                                 kAutoGenerateReturnID,
  132.                                 kAnyTransactionID,
  133.                                 &btchEvent );
  134.     
  135.     if ( err ){
  136.         Gripe( "\pcreate btch event failed" );
  137.         return err;
  138.     }
  139.     err = AEDisposeDesc( spellerAddrPtr );
  140.     if ( err ){
  141.         Gripe( "\pAEDisposeDesc failed" );
  142.         return err;
  143.     }
  144.  
  145. #ifdef OLD_SPEC    
  146.  
  147.     /* This was used until 1.0d6 */
  148.  
  149.     /* Insert the object specifier as the direct object of the batch event */
  150.  
  151.     err = AEPutParamDesc( &btchEvent,
  152.                             keyDirectObject,
  153.                             &textSpecifier );
  154.     if ( err ){
  155.         Gripe( "\pAEPutParamDesc failed to put direct object on batch event" );
  156.         return err;
  157.     }
  158.     err = AEDisposeDesc( &textSpecifier );
  159.     if ( err ){
  160.         Gripe( "\pAEDisposeDesc failed" );
  161.         return err;
  162.     }
  163. #else
  164.  
  165.     /* 1.0d7 This is the new way to do it - use a list of object specifiers (even if
  166.      * only one of them
  167.      */
  168.     
  169.     err = AECreateList( (Ptr)NULL, (Size)0, false, &textSpecList );
  170.     if ( err ){
  171.         Gripe( "\pAECreateList failed" );
  172.         return err;
  173.     }
  174.     
  175.     /* Put our specifier into it.  If we had multiple text blocks to check, we would
  176.      * put specifiers for each into it in turn.
  177.      * Note that we use AEPutDesc, not AEPutParamDesc, to put items into an indexed
  178.      * list.
  179.      */
  180.  
  181. #define N_TEXT_SPECS    1L /*3L    */    /* Define this to be 1 for normal checking */
  182.  
  183.     for ( index = 1L; index <= N_TEXT_SPECS; index++ ){
  184.         err = AEPutDesc( &textSpecList,
  185.                             index,
  186.                             &textSpecifier );
  187.         if ( err ){
  188.             Gripe( "\pAEPutDesc failed to put text specifier into textSpecList" );
  189.             return err;
  190.         }
  191.     }
  192.  
  193.     err = AEDisposeDesc( &textSpecifier );
  194.     if ( err ){
  195.         Gripe( "\pAEDisposeDesc failed" );
  196.         return err;
  197.     }
  198.  
  199.     /* Insert the list of object specifiers as the direct object of the batch event */
  200.  
  201.     err = AEPutParamDesc( &btchEvent,
  202.                             keyDirectObject,
  203.                             &textSpecList );
  204.     if ( err ){
  205.         Gripe( "\pAEPutParamDesc failed to put direct object on batch event" );
  206.         return err;
  207.     }
  208.     err = AEDisposeDesc( &textSpecifier );
  209.     if ( err ){
  210.         Gripe( "\pAEDisposeDesc failed" );
  211.         return err;
  212.     }
  213. #endif
  214.  
  215.     /* Send the event.  We await the reply, so that if there is a failure of some
  216.      * sort in the initial connection, we can alert the user right away.  The timeout
  217.      * value to use here should be as long as one would care to have a user wait for
  218.      * the completion of a menu command.  Since we expect that the speller is on a local
  219.      * machine in this case, and should be able to respond immediately, we just give
  220.      * a few seconds for the timeout.
  221.      *
  222.      * We should assign an idle proc to spin the cursor.  Even better would be a progress
  223.      * dialog that says "Contacting speller" or some such, with an animated display that
  224.      * shows the time elapsed relative to the total timeout, so the user will know how
  225.      * long she may have to wait
  226.      */
  227.     
  228.     err = AESend( &btchEvent,
  229.                     &replyEvent,
  230.                     kAEWaitReply + kAECanInteract + kAECanSwitchLayer,
  231.                     kAENormalPriority,
  232.                     kBatchTimeout,
  233.                     (IdleProcPtr)NULL,
  234.                     (EventFilterProcPtr)NULL );
  235.     
  236.     if ( err ){
  237.         Gripe( "\psend batch event failed" );
  238.         return err;
  239.     }
  240.     err = AEDisposeDesc( &btchEvent );
  241.     if ( err ){
  242.         Gripe( "\pAEDisposeDesc failed" );
  243.         return err;
  244.     }
  245.     
  246.     /* Now the event has been sent.  There is nothing more that we have to actually do
  247.      * on our own initiative to accomplish the spelling; we just sit back and respond
  248.      * to events.  In particular, we don't remember that spelling is taking place - once
  249.      * the spelling is done, we will just start seeing events from the user (mouse and
  250.      * key clicks and so on
  251.      */
  252.     
  253.     return noErr;
  254. }
  255.  
  256. OSErr OpenSpeller( short serviceNumber,
  257.                     AEAddressDesc *spellerAddrPtr,
  258.                     ServiceType *servTypePtr )
  259. {
  260.     WWJrPrefsHdl    prefHdl;
  261.     short            servID;
  262.     AliasHandle        aliasHdl;
  263.     short            curFile;
  264.     OSType            signature;
  265.     ProcessSerialNumber psn;
  266.     ProcessInfoRec        pInfo;
  267.     OSErr            err;
  268.     
  269.     prefHdl = GetPrefHandle();
  270.     if ( !prefHdl ){
  271.         Gripe( "\pCannot get prefs handle" );
  272.         return resNotFound;
  273.     }
  274.     
  275.     servID = gServItemID[ serviceNumber - 1 ];        /* C arrays start at 0 */
  276.     
  277.     *servTypePtr = (*prefHdl)->serviceType[ servID - kServiceBaseID ];
  278.  
  279.     curFile = CurResFile();
  280.     UseResFile( gPrefFileRefNum );
  281.     
  282.     aliasHdl = (AliasHandle)GetResource( rAliasType, servID );
  283.  
  284.     UseResFile( curFile );
  285.  
  286.     if ( !aliasHdl ){
  287.         Gripe( "\pCannot get alias handle for service" );
  288.         return resNotFound;
  289.     }
  290.     
  291.     /* See if the speller is out there */
  292.     signature = (*aliasHdl)->userType;
  293.  
  294.     if ( !FindAProcess( signature, &psn, &pInfo, (FSSpecPtr)NULL, (StringPtr)NULL ) ){
  295.  
  296.         EventRecord event;
  297.         short        i;
  298.  
  299.         err = LaunchSpeller( aliasHdl );
  300.         if ( err ){
  301.             Gripe( "\pUnable to launch Word Services server" );
  302.             return err;
  303.         }
  304. #ifdef NEVER        
  305.         /* Got to sleep for a little while - otherwise the speller croaks */
  306.         for ( i = 0; i < 10; i++ )
  307.             WaitNextEvent( 0, &event, 1, (RgnHandle)NULL );
  308. #endif
  309.     }    
  310.  
  311.     err = AECreateDesc( typeApplSignature,
  312.                         (Ptr)&signature,
  313.                         sizeof( signature ),
  314.                         spellerAddrPtr );
  315.     if ( err ){
  316.         Gripe( "\pAECreateDesc failed" );
  317.         return err;
  318.     }
  319.     
  320.     return noErr;
  321. }
  322.  
  323. #ifdef LAUNCH_BY_EVENT
  324. OSErr LaunchSpeller( AliasHandle aliasHdl )
  325. {
  326.     OSErr        err;
  327.     FSSpec        spellerSpec;
  328.     Boolean        changed;
  329.     AppleEvent        launchEvent;
  330.     AppleEvent        replyEvent;
  331.     AEDesc            aliasDesc;
  332.     AEDesc            folderDesc;
  333.     FSSpec            folderSpec;
  334.     AEDesc            finderAddr;
  335.     DescType        finderSig;
  336.     AliasHandle        fAliasHdl;
  337.     AEDescList        aliasList;
  338.  
  339.     /* Make sure the speller can still be found, and get its spec */
  340.     err = ResolveAlias( (FSSpecPtr)NULL, aliasHdl, &spellerSpec, &changed );
  341.     
  342.     if ( err ){
  343.         Gripe( "\pCannot locate speller" );        /* Might be user canceled AShare */
  344.         return err;
  345.     }
  346.     
  347.     if ( changed ){
  348.         ChangedResource( aliasHdl );
  349.         WriteResource( aliasHdl );
  350.     }
  351.     
  352.     /* make an alias for the parent folder */
  353.     
  354.     err = FSMakeFSSpec( spellerSpec.vRefNum,
  355.                         spellerSpec.parID,
  356.                         (StringPtr)NULL,
  357.                         &folderSpec );
  358.     if ( err ){
  359.         Gripe( "\pMakeFSSpec failed" );
  360.         return err;
  361.     }
  362.     
  363.     err = NewAlias( (FSSpecPtr)NULL, &folderSpec, &fAliasHdl );
  364.     if ( err ){
  365.         Gripe( "\pNewAlias failed" );
  366.         return err;
  367.     }
  368.  
  369.     /* Create the event to send to the Finder */
  370.     
  371.     finderSig = 'MACS';                        /* Creator code of finder; type is 'FNDR' */
  372.     err = AECreateDesc( typeApplSignature,
  373.                         (Ptr)&finderSig,
  374.                         sizeof( finderSig ),
  375.                         &finderAddr );
  376.     if ( err ){
  377.         Gripe( "\pAECreateDesc failed" );
  378.         return err;
  379.     }    
  380.                 
  381.     err = AECreateAppleEvent( kAEFinderEvents,
  382.                                 kAEOpenSelection,
  383.                                 &finderAddr,
  384.                                 kAutoGenerateReturnID,
  385.                                 kAnyTransactionID,
  386.                                 &launchEvent );
  387.     
  388.     if ( err ){
  389.         Gripe( "\pcreate open selection event failed" );
  390.         return err;
  391.     }
  392.     err = AEDisposeDesc( &finderAddr );
  393.     if ( err ){
  394.         Gripe( "\pAEDisposeDesc failed" );
  395.         return err;
  396.     }
  397.     
  398.     /* Insert the folder alias record as the direct object of the batch event */
  399.  
  400.     /* First make a descriptor of the alias */
  401.     HLock( fAliasHdl );
  402.  
  403.     err = AECreateDesc( typeAlias,
  404.                         (Ptr)*fAliasHdl,
  405.                         (*fAliasHdl)->aliasSize,
  406.                         &folderDesc );
  407.  
  408.     HUnlock( fAliasHdl );
  409.     DisposHandle( fAliasHdl );
  410.  
  411.     if ( err ){
  412.         Gripe( "\pAECreateDesc failed" );
  413.         return err;
  414.     }    
  415.     
  416.     err = AEPutParamDesc( &launchEvent,
  417.                             keyDirectObject,
  418.                             &folderDesc );
  419.     if ( err ){
  420.         Gripe( "\pAEPutParamDesc failed to put direct object on open selection event" );
  421.         return err;
  422.     }
  423.     err = AEDisposeDesc( &folderDesc );
  424.     if ( err ){
  425.         Gripe( "\pAEDisposeDesc failed" );
  426.         return err;
  427.     }
  428.  
  429.     /* Put the application alias on the event */
  430.     HLock( aliasHdl );
  431.  
  432.     err = AECreateDesc( typeAlias,
  433.                         (Ptr)*aliasHdl,
  434.                         (*aliasHdl)->aliasSize,
  435.                         &aliasDesc );
  436.  
  437.     HUnlock( aliasHdl );
  438.  
  439.     if ( err ){
  440.         Gripe( "\pAECreateDesc failed" );
  441.         return err;
  442.     }    
  443.  
  444.     /* Now make a list of the alias descriptor.  There is only one element in this
  445.      * list
  446.      */
  447.     
  448.     err = AECreateList( (Ptr)NULL, (Size)0, false, &aliasList );
  449.     
  450.     if ( err ){
  451.         Gripe( "\pAECreateList failed" );
  452.         return err;
  453.     }
  454.     
  455.     err = AEPutDesc( &aliasList, 1L, &aliasDesc );
  456.     
  457.     if ( err ){
  458.         Gripe( "\pAEPutDesc failed to put alias into alias list" );
  459.         return err;
  460.     }
  461.  
  462.     err = AEDisposeDesc( &aliasDesc );
  463.     if ( err ){
  464.         Gripe( "\pAEDisposeDesc failed" );
  465.         return err;
  466.     }
  467.     
  468.     err = AEPutParamDesc( &launchEvent,
  469.                             keySelection,
  470.                             &aliasList );
  471.     if ( err ){
  472.         Gripe( "\pAEPutParamDesc failed to put keySelection on open selection event" );
  473.         return err;
  474.     }
  475.  
  476.     err = AEDisposeDesc( &aliasList );
  477.     if ( err ){
  478.         Gripe( "\pAEDisposeDesc failed" );
  479.         return err;
  480.     }
  481.  
  482.     err = AESend( &launchEvent,
  483.                     &replyEvent,
  484.                     kAEWaitReply + kAECanInteract,        /* Don't allow later switch */
  485.                     kAENormalPriority,
  486.                     kLaunchTimeout,
  487.                     (IdleProcPtr)NULL,
  488.                     (EventFilterProcPtr)NULL );
  489.     
  490.     if ( err ){
  491.         Gripe( "\psend open selection event failed" );
  492.         return err;
  493.     }
  494.     err = AEDisposeDesc( &launchEvent );
  495.     if ( err ){
  496.         Gripe( "\pAEDisposeDesc failed" );
  497.         return err;
  498.     }
  499.     
  500.     return noErr;
  501. }
  502. #else
  503.  
  504. /* This makes the speller fail to process the batch event - I don't know why */
  505.  
  506. OSErr LaunchSpeller( AliasHandle aliasHdl )
  507. {
  508.     LaunchParamBlockRec    pb;
  509.     OSErr        err;
  510.     FSSpec        spellerSpec;
  511.     Boolean        changed;
  512.     char        *cPtr;
  513.     short        i;
  514.     
  515.     /* Make sure the speller can still be found */
  516.     err = ResolveAlias( (FSSpecPtr)NULL, aliasHdl, &spellerSpec, &changed );
  517.     
  518.     if ( err ){
  519.         Gripe( "\pCannot locate speller" );        /* Might be user canceled AShare */
  520.         return err;
  521.     }
  522.     
  523.     if ( changed ){
  524.         ChangedResource( aliasHdl );
  525.         WriteResource( aliasHdl );
  526.     }
  527.     
  528.     cPtr = (char*)&pb;
  529.     
  530.     for ( i = 0; i < sizeof( pb ); i++ ){
  531.         *cPtr++ = 0;
  532.     }
  533.  
  534.     pb.launchBlockID = extendedBlock;
  535.     pb.launchEPBLength = extendedBlockLen;
  536.     pb.launchControlFlags = launchNoFileFlags + launchContinue /*+ launchDontSwitch*/;
  537.     pb.launchAppSpec = &spellerSpec;
  538.     pb.launchAppParameters = NULL;
  539.     
  540.     err = LaunchApplication( &pb );
  541.     
  542.     if ( err == memFullErr ){
  543.     
  544.         Gripe( "\pThere is not enough memory to launch the Word Services server" );
  545.         return err;
  546.     }
  547.     
  548.     if ( err ){
  549.         Gripe( "\pUnable to launch the Word Services server" );
  550.         return err;
  551.     }
  552.  
  553.     return noErr;
  554. }
  555.  
  556. #endif /* LAUNCH_BY_EVENT */